package veetouch.network;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.DataInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.Socket;
import java.net.URL;
import java.net.URLConnection;
import java.net.UnknownHostException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import veetouch.shareimage.ShareImageActivity;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.widget.Toast;

public class NetworkConncetion extends Thread
{
	private String address;
	private int port;
	
	private Socket socket;
	private InputStream in;
	private DataInputStream dis;
	private BufferedOutputStream out;
	
	private ShareImageActivity imageActivity;
	
	//private static Pattern imagePattern = Pattern.compile("<type>(jpg|JPG|png|PNG)</type><data>([0-9]+)</data>");
	private static Pattern imagePattern = Pattern.compile("<type>image</type><data>(.*?)</data>");
	private static Pattern exitPattern  = Pattern.compile("<type>exit</type>");
	
	public boolean runProcess = true; // Change to false when want to destroy thread
	
	public NetworkConncetion(ShareImageActivity imageActivity)
	{
		this.imageActivity = imageActivity;
	}
	
	public void openConnection()
	{
		try 
		{
			this.socket = new Socket(this.address,this.port);
			 // Again, probably better to store these objects references in the support class
		    in = socket.getInputStream();
		    dis = new DataInputStream(in);
		    out = new BufferedOutputStream( this.socket.getOutputStream() );
			this.start();
		} 
		catch (UnknownHostException e) 
		{
			this.imageActivity.showDialog(0);
		} 
		catch (IOException e) 
		{
			this.imageActivity.showDialog(0);
		}
	}
	
	public void closeConnection()
	{
		try 
		{
			this.runProcess = false;
			this.in.close();
			this.dis.close();
			this.out.close();
			this.socket.close();
		}
		catch (IOException e) 
		{
			
		}
	}
	
	public boolean isConnect()
	{
		if(this.socket == null)
			return false;
		return this.socket.isConnected();
	}

	public String getAddress() {
		return address;
	}

	public void setAddress(String address) {
		this.address = address;
	}

	public int getPort() {
		return port;
	}

	public void setPort(int port) {
		this.port = port;
	}
	
	public byte[] readBytes()
	{
		byte[] data;
		try 
		{
			data = new byte[dis.available()];
			dis.readFully(data);
			return data;
		}
		catch (IOException e) 
		{
			// Connection lost
			closeConnection();
			this.imageActivity.runOnUiThread(new Runnable() 
			{
				public void run() 
				{
					imageActivity.showDialog(0);
				}
			});
			return new byte[0];
		}
	}
	
	public void sendExitMessage()
	{
		try 
		{
			String msg = "<type>exit</type>";
			out.write(msg.getBytes());
			out.flush();
		}
		catch (IOException e) 
		{
			
		}
	}
	
	public void sendImage(String imagePath)
    {
	   try 
	   {
		   //BufferedOutputStream out = new BufferedOutputStream( this.socket.getOutputStream() );
		   BufferedInputStream reader;
		   reader = new BufferedInputStream( new FileInputStream( imagePath ) );
		   // reader = new BufferedInputStream( new FileInputStream( "image_small.jpg" ) );
		   
		   String fileType = "jpg";
		   if(imagePath.endsWith("jpg") || imagePath.endsWith("JPG"))
		   {
			   fileType = "jpg";
		   }
		   else if(imagePath.endsWith("png") || imagePath.endsWith("PNG"))
		   {
			   fileType = "png";
		   }
		   
		   // 1. Send file type,file size
		   String fileProp = "<type>"+fileType+"</type><data>"+reader.available()+"</data>";
		   out.write(fileProp.getBytes());

		   // 2. Send file data
		   byte[] buffer = new byte[ reader.available() ];
		   reader.read(buffer);
		   out.write(buffer);
		   out.flush();
	   }
	   catch (IOException e) 
	   {
		   // Network lost
		   closeConnection();
		   this.imageActivity.runOnUiThread(new Runnable() 
		   {
			   public void run() 
			   {
				   imageActivity.showDialog(0);
			   }
		   });
	   }
   }
	
	public void run()
	{
		byte[] allData = new byte[0];
		while(this.isConnect() && this.runProcess)
		{
			synchronized(this)
	        {
				byte[] data = readBytes();
				if(data.length == 0)
				{
					continue;
				}
				
				allData = NetworkConncetion.concat(allData, data);
				
				String strAllData = new String(allData);
				Matcher matcherType = imagePattern.matcher(strAllData);
				if(matcherType.find())
				{
					final String imageName = generateImagefileName()+".jpg";
			        BitmapFactory.Options bmOptions = new BitmapFactory.Options();
					bmOptions.inSampleSize = 1;
					Bitmap bm = LoadImage(matcherType.group(1), bmOptions);
					saveImageToSD(bm,imageName);
					
					// Toast for warn user that receive image
					this.imageActivity.runOnUiThread(new Runnable() 
					{
						public void run() 
						{
							// Try to Update Gallery
							imageActivity.addNewImageToGallery("/sdcard/vSync/"+imageName);
							Toast toast = Toast.makeText(imageActivity.getApplicationContext(),"Receive image",Toast.LENGTH_LONG);
							toast.show();
						}
					});
				}
				else
				{
					Matcher matcherExit = exitPattern.matcher(strAllData);
					if(matcherExit.find())
					{
						// Server close socket
						closeConnection();
						this.imageActivity.runOnUiThread(new Runnable() 
						{
							public void run() 
							{
								imageActivity.showDialog(0);
							}
						});
						return;
					}
				}
	        }
		}
		try 
		{
			this.socket.close();
			this.stop();
		}
		catch (IOException e) 
		{
			
		}
	}
	
	public static byte[] concat(byte[] allData, byte[] data) 
	{
		byte[] result = new byte[allData.length + data.length];
		System.arraycopy(allData, 0, result, 0, allData.length);
		System.arraycopy(data, 0, result, allData.length, data.length);
		return result;
	}
	
	
	public static String generateImagefileName()
	{
	    Calendar cal = Calendar.getInstance();
	    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH.mm.ss");
	    return sdf.format(cal.getTime());
	}
	
	public Bitmap LoadImage(String URL, BitmapFactory.Options options)
	{
		Bitmap bitmap  = null;
		InputStream in = null;
		try 
		{
	        in = OpenHttpConnection(URL);
			//bitmap = BitmapFactory.decodeStream(in, null, options);
			bitmap = BitmapFactory.decodeStream(new PatchInputStream(in));
	        in.close();
		}
		catch (IOException e1) 
		{
			
	    }
	    return bitmap;
	}
	
	private InputStream OpenHttpConnection(String strURL) throws IOException
	{
		 InputStream inputStream = null;
		 URL url = new URL(strURL);
		 URLConnection conn = url.openConnection();
		 try
		 {
			 HttpURLConnection httpConn = (HttpURLConnection)conn;
			 httpConn.setRequestMethod("GET");
			 httpConn.connect();
			 if (httpConn.getResponseCode() == HttpURLConnection.HTTP_OK) 
			 {
				 inputStream = httpConn.getInputStream();
			 }
		 }
		 catch (Exception ex)
		 {
		 }
		 return inputStream;
	}
	
	// Save Image
	public void saveImageToSD(Bitmap bm,String imageName)
	{
		FileOutputStream outStream = null;
		File file = new File("/sdcard/vSync/",imageName);
		//File file = new File("/sdcard/vSync/", "test.jpg");
		try 
		{
			file.getParentFile().mkdirs();
			file.createNewFile();
			
			outStream = new FileOutputStream(file);
			bm.compress(Bitmap.CompressFormat.JPEG, 100, outStream);
		    outStream.flush();
		    outStream.close();
		    // Toast.makeText(AndroidWebImage.this, "Saved", Toast.LENGTH_LONG).show();
		} 
		catch (FileNotFoundException e) 
		{
			//Toast.makeText(AndroidWebImage.this, e.toString(), Toast.LENGTH_LONG).show();
		} 
		catch (IOException e) {
			// Toast.makeText(AndroidWebImage.this, e.toString(), Toast.LENGTH_LONG).show();
		}
	}
}
